﻿#include "OiPCH.hpp"

namespace Oi
{
    namespace PLScannerCore
    {
        class DSPlcTaskImpl : public Impl<DSPlcTask>
        {
        public:
            void init();

        public:
            QString _formular;
            QString _preset;
            double _width;
            double _circum;
            ushort _startSignal;

            QList<PLScannerOutput> _wDatas;

            QMutex _mutex;
            bool _quit;

        public:
            bool _simulation;
            bool _plcEnable;
            QString _deviceName;
            QString _addr;
            QString _port;
            QString _args;

        };

        void DSPlcTaskImpl::init()
        {
            OI_Q(DSPlcTask);

            _quit = false;

            
        }


        DSPlcTask::DSPlcTask(QObject* parent) 
            : QThread(parent)
        {
            OI_I(DSPlcTask)->init();
            
            init();
        }

        DSPlcTask::~DSPlcTask()
        {
            OI_E(DSPlcTask);

            exit();
        }

        void DSPlcTask::init()
        {
            OI_F(DSPlcTask);
            auto settings = Core::OiSettings();

            d->_simulation = PLScanner::instance()->simulation;
            d->_plcEnable = settings->value("PLC/Enable", false).toBool();

            d->_deviceName = Core::OiSettings()->value("PLC/DeviceName", "PLC_DS_MC").toString();
            d->_addr = Core::OiSettings()->value("PLC/Address", "10.10.61.180").toString();
            d->_port = Core::OiSettings()->value("PLC/Port", "5000").toString();
            d->_args = Core::OiSettings()->value("PLC/Args", "comm=udp&frame=3E&ascii=0&network_number=0&pc_number=255").toString();

            if(!d->_simulation && d->_plcEnable)
            {
                start();
            }
        }

        void DSPlcTask::exit()
        {
            if(isRunning())
            {
                quit();
                wait();
            }
        }

        void DSPlcTask::run()
        {
            OI_F(DSPlcTask);

            bool quit = false;
            int action;
            PLScannerOutput output;

            if(d->_simulation || !d->_plcEnable)
            {
                return;
            }

            QSharedPointer<Util::PLC> device = Util::PLCService::instance()->get(qPrintable(d->_deviceName));

            std::string path;
            path += "protocol=melsec";
            path += "&addr=" + d->_addr.toStdString();
            path += "&port=" + d->_port.toStdString();
            path += "&" + d->_args.toStdString();

            if(device.isNull())
            {
                device = Util::PLC::create(qPrintable(d->_deviceName), path.c_str());
                Util::PLCService::instance()->add(qPrintable(d->_deviceName), device);
            }

            if(!device->isValid() || device->connect() != 0)
            {
                PLScannerError::instance()->reportError(PLScannerError::ERR_PLC_INVALID);
                return;
            }

            while(!quit)
            {
                d->_mutex.lock();
                quit = d->_quit;
                action = d->_wDatas.size();

                if(action != 0)
                {
                    output = d->_wDatas.front();
                    d->_wDatas.pop_front();
                }

                d->_mutex.unlock();

                if(action != 0)
                {
                    std::vector<int16_t> resData(1);
                    resData[0] = output.result;

                    if(device->set("D", resData.data(), 3060, 1) == 0)
                    {
                    }
                    else
                    {
                        PLScannerError::instance()->reportError(PLScannerError::ERR_PLC_TIMEOUT);
                    }

                    std::vector<float> valueData(13);
                    memcpy(valueData.data(), (char*)&output + sizeof(output.result), 13 * sizeof(float));

                    if(device->set("D", valueData.data(), 3062, 13) == 0)
                    {
                    }
                    else
                    {
                        PLScannerError::instance()->reportError(PLScannerError::ERR_PLC_TIMEOUT);
                    }

                    if (output.curve.size() > 0)
                    {
                        if(device->set("D", output.curve.data(), 4000, output.curve.size()) == 0)
                        {
                        }
                        else
                        {
                            PLScannerError::instance()->reportError(PLScannerError::ERR_PLC_TIMEOUT);
                        }

                    }
//                     std::vector<int16_t> resetData(1);
//                     resetData[0] = 0;
// 
//                     if(device->set("D", resetData.data(), 3050, 1) == 0)
//                     {
//                     }
//                     else
//                     {
//                         PLScannerError::instance()->reportError(PLScannerError::ERR_PLC_TIMEOUT);
//                     }
                    //mark
                    QThread::msleep(10);
                }
                else
                {
                    QString formular;
                    QString preset;
                    double width = 0.0;
                    double circum = 0.0;
                    ushort startSignal = 0;

//                     std::string formularData(20, 0);
//                     if(device->get("D", formularData, 3000, 20) == 0)
//                     {
//                         formular = QString::fromStdString(formularData);
//                     }
//                     else
//                     {
//                         PLScannerError::instance()->reportError(PLScannerError::ERR_PLC_TIMEOUT);
//                     }
                    formular = "Default";
                    preset = "Default";

//                     std::string presetData(20, 0);
//                     if(device->get("D", presetData, 3020, 20) == 0)
//                     {
//                         preset = QString::fromStdString(presetData);
//                     }
//                     else
//                     {
//                         PLScannerError::instance()->reportError(PLScannerError::ERR_PLC_TIMEOUT);
//                     }

                    std::vector<uint16_t> wData(1);
                    if(device->get("D", wData.data(), 3040, 1) == 0)
                    {
                        width = 0.1 * wData[0];
                    }
                    else
                    {
                        PLScannerError::instance()->reportError(PLScannerError::ERR_PLC_TIMEOUT);
                    }

                    std::vector<uint16_t> cData(1);
                    if(device->get("D", cData.data(), 3042, 1) == 0)
                    {
                        circum = cData[0];
                    }
                    else
                    {
                        PLScannerError::instance()->reportError(PLScannerError::ERR_PLC_TIMEOUT);
                    }

                    std::vector<uint16_t> ssData(1);
                    if(device->get("D", ssData.data(), 3050, 1) == 0)
                    {
                        startSignal = ssData[0];
                    }
                    else
                    {
                        PLScannerError::instance()->reportError(PLScannerError::ERR_PLC_TIMEOUT);
                    }

                    d->_mutex.lock();
                    d->_formular = formular;
                    d->_preset = preset;
                    d->_width = width;
                    d->_circum = circum;
                    d->_startSignal = startSignal;
                    d->_mutex.unlock();

                    QThread::msleep(10);
                }
            }

            Util::PLCService::instance()->exit();
        }

        void DSPlcTask::quit()
        {
            OI_F(DSPlcTask);
            QMutexLocker lock(&d->_mutex);
            d->_quit = true;
        }

        void DSPlcTask::start()
        {
            OI_F(DSPlcTask);
            d->_mutex.lock();
            d->_quit = false;
            d->_wDatas.clear();
            d->_mutex.unlock();

            QThread::start();
        }

        bool DSPlcTask::write(const PLScannerOutput& ouput)
        {
            OI_F(DSPlcTask);

            if(d->_simulation || !d->_plcEnable)
            {
                return true;
            }

            if(!isRunning())
            {
                start();
            }

            QMutexLocker lock(&d->_mutex);
            d->_wDatas.push_back(ouput);

            return true;
        }

        bool DSPlcTask::readParams(ProductParams& params)
        {
            OI_F(DSPlcTask);

            QString formular;
            QString preset;
            double width = 0.0;
            double circum = 0.0;

            d->_mutex.lock();
            formular = d->_formular;
            preset = d->_preset;
            width = d->_width;
            circum = d->_circum;
            d->_mutex.unlock();

            formular.remove(QChar(0));
            preset.remove(QChar(0));
            formular = formular.simplified();
            preset = preset.simplified();

            if(width == 0.0 || circum == 0.0 || formular.isEmpty() || preset.isEmpty())
            {
                OiWarning() << "参数读取错误，" << "Width:" << width << "circum:" << circum << " preset:" << preset << " formular:" << formular;
                return false;
            }

            params = ProductParams(width, circum / (2 * M_PI), formular, preset);
            return true;
        }

        bool DSPlcTask::readStatus(ProductStatus& status)
        {
            OI_F(DSPlcTask);

            double startSignal = 0;

            d->_mutex.lock();
            startSignal = d->_startSignal;
            d->_mutex.unlock();

            status.enable = ( startSignal == 1 );
            return true;
        }

        DSPlcTask* DSPlcTask::instance()
        {
            static DSPlcTask s_plc;
            return &s_plc;
        }

    }
}